#include "Dictionary.hh"
#include "Configuration.hh"
#include "Log/Log.hh"
#include <fstream>
#include <sstream>

using std::ifstream;
using std::ofstream;
using std::string;
using std::istringstream;


Dictionary* Dictionary::_instance = nullptr;
size_t nBytesCode(const char ch);

std::size_t length(const std::string &str);
Dictionary* Dictionary::createInstance(){
    if(_instance == nullptr){
        _instance = new Dictionary();
    }
    return _instance;
}

void Dictionary::destoryDict(){
    if(_instance != nullptr){
        delete _instance;
        _instance = nullptr;
    }
}


Dictionary::Dictionary() {
    auto& conf_map = Configuration::createConfig()->getConfigMap();

    init(conf_map["dict_path_en"][0]);
    Log::info("英文词典加载成功");

    init(conf_map["dict_path_zh"][0]);
    Log::info("中文词典加载成功");

    initIndexTable(conf_map["dictIndex"][0]);
    Log::info("词典索引加载成功");
};


void Dictionary::init(const string& dictpath){
    // 读入词典
    ifstream ifs(dictpath);

    while(ifs){
        string word;
        int freq;
        ifs >> word;
        ifs >> freq;

        _dict.push_back({word, freq});
    }
}
vector<pair<string, size_t>>& Dictionary::getDict(){
    return _dict;
}
map<string, set<size_t>>& Dictionary::getIndexTable(){
    return _indexTable;
}

void Dictionary::initIndexTable(const string& indexpath){
    ifstream ifs(indexpath);
    Log::debug(indexpath);
    string line;
    while(getline(ifs, line)){
        istringstream iss(line);

        while(iss){
            string word;
            int freq;
            iss >> word;
            while(iss >> freq){
                _indexTable[word].insert(freq + 1);
            }
        }
    }

}


set<int> Dictionary::doQuery(const string& word){
    vector<string> result;
    for(size_t i = 0; i < word.size();){
        size_t size = nBytesCode(word[i]);
        result.push_back(word.substr(i, size));

        i += size;
    }

    set<int> s;
    for(auto& item : result){
        
        auto& ret = _indexTable[item]; 
        for(auto& elem : ret){
            s.insert(elem);
        }
    }
    Log::debug(word);
    return s;
}

inline size_t nBytesCode(const char ch)
{
	if(ch & (1 << 7))
	{
		int nBytes = 1;
		for(int idx = 0; idx != 6; ++idx)
		{
			if(ch & (1 << (6 - idx)))
			{
				++nBytes;	
			}
			else
				break;
		}
		return nBytes;
	}
	return 1;
}  


inline std::size_t length(const std::string &str)
{
	std::size_t ilen = 0;
	for(std::size_t idx = 0; idx != str.size(); ++idx)
	{
		int nBytes = nBytesCode(str[idx]);
		idx += (nBytes - 1);
		++ilen;
	}
	return ilen;
}
